package com.blog.utils;

import com.blog.config.Appconfig;
import com.blog.entity.Users;
import com.blog.mapper.UsersMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class JwtTokenProvider {

    private final Appconfig appconfig;

    private SecretKey secretKey;

    @Resource
    private UsersMapper usersMapper;
    @Resource
    private RedisUtils redisUtils;

    public JwtTokenProvider(Appconfig appconfig) {
        this.appconfig = appconfig;
    }

    @PostConstruct
    public void init() {
        // 将字符串密钥转换为安全的 SecretKey
        this.secretKey = Keys.hmacShaKeyFor(appconfig.getSecretKey().getBytes(StandardCharsets.UTF_8));
    }

    // 生成 Token
    public String generateToken(String email,List<GrantedAuthority> authorities,long expirationtime) {

        return Jwts.builder()
                .claim("authorities", authorities)
                .setSubject(email)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expirationtime))
                .signWith(secretKey)
                .compact();
    }

    // 解析 Token 获取Email
    public String getEmailFromToken(String token) {
        return parseToken(token).getSubject();
    }

    //解析 Token 获取用户名
    public String getUsernameFromToken(String token) {
        String email = getEmailFromToken(token);
        return usersMapper.findByEmail(email).getNickname();
    }

    // 解析token获取权限信息
    @SuppressWarnings("unchecked")
    public List<GrantedAuthority> getAuthoritiesFromToken(String token) {
        List<Map<String, String>> authorityMaps = (List<Map<String, String>>) parseToken(token).get("authorities");
        List<GrantedAuthority> authorities = new ArrayList<>();

        if (authorityMaps != null) {
            for (Map<String, String> authMap : authorityMaps) {
                authorities.add(new SimpleGrantedAuthority(authMap.get("authority")));
            }
        }
        return authorities;
    }

    // 验证 Token 是否有效，1为短期token，2为长期token
    public boolean validateToken(String token,Integer status) {
        try {
            //1. 验证是否有效
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            //2. 如果是短期token是否已经登出,为无效token
            try{
                String s = redisUtils.get("shorttoken" + token).toString();
            } catch (Exception e) {
                log.info(" " + e);
            }

            if(status == 1 && redisUtils.get("shorttoken" + token) == null) {
                throw new JwtException("用户已登出,token无效");
            }

            // 3. 验证过期时间
            Date expiration = claims.getExpiration();
            if (expiration.before(new Date())) {
                throw new JwtException("Token已经过期");
            }
            return true;
        } catch (Exception e) {
            log.error("Unexpected error validating token: {}", e.getMessage());
            return false;
        }
    }

    // 私有方法：解析token
    private Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    public String refreshToken(String refreshToken) {
        if(redisUtils.get("token" + refreshToken) != null) {
            redisUtils.delete("token" + refreshToken);
        }
        return generateToken(getEmailFromToken(refreshToken),getAuthoritiesFromToken(refreshToken),600000);
    }
}